﻿// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using Silverlight.Windows.Controls.Primitives;

namespace Silverlight.Windows.Controls
{
    /// <summary>
    /// Represents a pop-up menu that enables a control to expose functionality that is specific to the context of the control.
    /// </summary>
    /// <QualityBand>Preview</QualityBand>
    public class ContextMenu : ContextMenuBase
    {
        public ContextMenu()
            : base()
        {
            DefaultStyleKey = typeof(ContextMenu);
        }

        /// <summary>
        /// Updates the location and size of the Popup and overlay.
        /// </summary>
        protected override void UpdateContextMenuPlacement()
        {
            if ((null != _rootVisual) && (null != _overlay))
            {
                // Start with the current Popup alignment point
                double x = _popupAlignmentPoint.X;
                double y = _popupAlignmentPoint.Y;
                // Adjust for offset
                x += HorizontalOffset;
                y += VerticalOffset;
                // Try not to let it stick out too far to the right/bottom
                x = Math.Min(x, _rootVisual.ActualWidth - ActualWidth);
                y = Math.Min(y, _rootVisual.ActualHeight - ActualHeight);
                // Do not let it stick out too far to the left/top
                x = Math.Max(x, 0);
                y = Math.Max(y, 0);
                // Set the new location
                Canvas.SetLeft(this, x);
                Canvas.SetTop(this, y);
                // Size the overlay to match the new container
                _overlay.Width = _rootVisual.ActualWidth;
                _overlay.Height = _rootVisual.ActualHeight;
            }
        }

        /// <summary>
        /// Opens the Popup.
        /// </summary>
        /// <param name="position">Position to place the Popup.</param>
        protected override void OpenPopup(Point position)
        {
            ClosePopup();

            _popupAlignmentPoint = position;

            _overlay = new Canvas { Background = new SolidColorBrush(Colors.Transparent) };
            _overlay.MouseLeftButtonDown += HandleOverlayMouseButtonDown;
            _overlay.MouseRightButtonDown += HandleOverlayRightMouseButtonDown;
            _overlay.Children.Add(this);

            _popup = new Popup { Child = _overlay };
            if (Application.Current.IsRunningOutOfBrowser &&
                Application.Current.HasElevatedPermissions)
            {
                _popup.SetWindow(_currentWindow);
            }

            SizeChanged += HandleContextMenuOrRootVisualSizeChanged;
            if (null != _rootVisual)
            {
                _rootVisual.SizeChanged += HandleContextMenuOrRootVisualSizeChanged;
            }
            UpdateContextMenuPlacement();

            if (ReadLocalValue(DataContextProperty) == DependencyProperty.UnsetValue)
            {
                DependencyObject dataContextSource = Owner ?? _rootVisual;
                SetBinding(DataContextProperty, new Binding("DataContext") { Source = dataContextSource });
            }

            _popup.IsOpen = true;
            Focus();

            // Update IsOpen
            _settingIsOpen = true;
            IsOpen = true;
            _settingIsOpen = false;

            OnOpened(new RoutedEventArgs());
        }

        /// <summary>
        /// Closes the Popup.
        /// </summary>
        protected override void ClosePopup()
        {
            if (null != _popup)
            {
                _popup.IsOpen = false;
                _popup.Child = null;
                _popup = null;
            }
            if (null != _overlay)
            {
                _overlay.Children.Clear();
                _overlay = null;
            }
            SizeChanged -= HandleContextMenuOrRootVisualSizeChanged;
            if (null != _rootVisual)
            {
                _rootVisual.SizeChanged -= HandleContextMenuOrRootVisualSizeChanged;
            }

            // Update IsOpen
            _settingIsOpen = true;
            IsOpen = false;
            _settingIsOpen = false;

            OnClosed(new RoutedEventArgs());
        }

        protected override object GetFocusedElement()
        {
            return
                Application.Current.IsRunningOutOfBrowser &&
                Application.Current.HasElevatedPermissions
                ? FocusManager.GetFocusedElement(_currentWindow)
                : FocusManager.GetFocusedElement();
        }
    }
}
